package com.tcm.smarthealth.service.impl;

import com.tcm.smarthealth.document.ImageRecord;
import com.tcm.smarthealth.dto.dashboard.DashboardHeroResponse;
import com.tcm.smarthealth.dto.dashboard.DashboardInsightResponse;
import com.tcm.smarthealth.dto.dashboard.DashboardOverviewResponse;
import com.tcm.smarthealth.dto.dashboard.DashboardProgressItemResponse;
import com.tcm.smarthealth.dto.dashboard.DashboardRoadmapItemResponse;
import com.tcm.smarthealth.dto.dashboard.DashboardStatCardResponse;
import com.tcm.smarthealth.dto.dashboard.DashboardTrendMetricResponse;
import com.tcm.smarthealth.entity.Question;
import com.tcm.smarthealth.enums.QuestionType;
import com.tcm.smarthealth.service.DashboardService;
import com.tcm.smarthealth.service.QuestionService;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

@Service
public class DashboardServiceImpl implements DashboardService {

    private static final int DAILY_QUESTION_TARGET = 60;
    private static final int DAILY_IMAGE_TARGET = 24;
    private static final int WEEKLY_QUESTION_TARGET = 280;

    private final QuestionService questionService;
    private final MongoTemplate mongoTemplate;

    public DashboardServiceImpl(QuestionService questionService, MongoTemplate mongoTemplate) {
        this.questionService = questionService;
        this.mongoTemplate = mongoTemplate;
    }

    @Override
    public DashboardOverviewResponse fetchOverview(Long userId) {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime startOfToday = now.toLocalDate().atStartOfDay();
        LocalDateTime startOfYesterday = startOfToday.minusDays(1);
        LocalDateTime weekStart = LocalDate.now().minusDays(6).atStartOfDay();
        LocalDateTime previousWeekStart = weekStart.minusDays(7);

        long questionsToday = questionService.lambdaQuery()
                .eq(Question::getUserId, userId)
                .ge(Question::getCreatedAt, startOfToday)
                .count();

        long questionsYesterday = questionService.lambdaQuery()
                .eq(Question::getUserId, userId)
                .ge(Question::getCreatedAt, startOfYesterday)
                .lt(Question::getCreatedAt, startOfToday)
                .count();

        long questionsThisWeek = questionService.lambdaQuery()
                .eq(Question::getUserId, userId)
                .ge(Question::getCreatedAt, weekStart)
                .count();

        long questionsPrevWeek = questionService.lambdaQuery()
                .eq(Question::getUserId, userId)
                .ge(Question::getCreatedAt, previousWeekStart)
                .lt(Question::getCreatedAt, weekStart)
                .count();

        long totalQuestions = questionService.lambdaQuery()
                .eq(Question::getUserId, userId)
                .count();

        long answeredQuestions = questionService.lambdaQuery()
                .eq(Question::getUserId, userId)
                .isNotNull(Question::getAnswer)
                .ne(Question::getAnswer, "")
                .count();

        long answeredCurrentWeek = questionService.lambdaQuery()
                .eq(Question::getUserId, userId)
                .ge(Question::getCreatedAt, weekStart)
                .isNotNull(Question::getAnswer)
                .ne(Question::getAnswer, "")
                .count();

        long answeredPrevWeek = questionService.lambdaQuery()
                .eq(Question::getUserId, userId)
                .ge(Question::getCreatedAt, previousWeekStart)
                .lt(Question::getCreatedAt, weekStart)
                .isNotNull(Question::getAnswer)
                .ne(Question::getAnswer, "")
                .count();

        Query todayImagesQuery = Query.query(Criteria.where("user_id").is(userId)
                .and("created_at").gte(toDate(startOfToday)));
        long imagesToday = mongoTemplate.count(todayImagesQuery, ImageRecord.class);

        Query yesterdayImagesQuery = Query.query(Criteria.where("user_id").is(userId)
                .and("created_at").gte(toDate(startOfYesterday))
                .lt(toDate(startOfToday)));
        long imagesYesterday = mongoTemplate.count(yesterdayImagesQuery, ImageRecord.class);

        List<Question> recentQuestions = questionService.lambdaQuery()
                .eq(Question::getUserId, userId)
                .orderByDesc(Question::getCreatedAt)
                .last("LIMIT 3")
                .list();

        List<Question> confidenceSamples = questionService.lambdaQuery()
                .eq(Question::getUserId, userId)
                .orderByDesc(Question::getCreatedAt)
                .last("LIMIT 50")
                .list();

        List<Question> previousConfidenceSamples = questionService.lambdaQuery()
                .eq(Question::getUserId, userId)
                .lt(Question::getCreatedAt, weekStart)
                .orderByDesc(Question::getCreatedAt)
                .last("LIMIT 50")
                .list();

        List<ImageRecord> imageConfidenceSamples = mongoTemplate.find(Query.query(
                        Criteria.where("user_id").is(userId))
                .with(Sort.by(Sort.Direction.DESC, "created_at"))
                .limit(50), ImageRecord.class);

        double avgQuestionConfidence = averageConfidenceFromQuestions(confidenceSamples);
        double prevAvgQuestionConfidence = averageConfidenceFromQuestions(previousConfidenceSamples);
        double avgImageConfidence = averageConfidenceFromImages(imageConfidenceSamples);

        double coverageOverall = totalQuestions == 0 ? 0 : (answeredQuestions * 100.0 / totalQuestions);
        double coverageCurrentWeek = questionsThisWeek == 0 ? 0 : (answeredCurrentWeek * 100.0 / questionsThisWeek);
        double coveragePrevWeek = questionsPrevWeek == 0 ? 0 : (answeredPrevWeek * 100.0 / questionsPrevWeek);
        double coverageDelta = coverageCurrentWeek - coveragePrevWeek;

        double questionTrend = percentageChange(questionsToday, questionsYesterday);
        double imageTrend = percentageChange(imagesToday, imagesYesterday);
        double weeklyGrowth = percentageChange(questionsThisWeek, questionsPrevWeek);
        double confidenceDelta = (avgQuestionConfidence - prevAvgQuestionConfidence) * 100;

        DashboardOverviewResponse response = new DashboardOverviewResponse();
        response.setHero(buildHero(questionsToday, imagesToday, coverageOverall, avgQuestionConfidence));
        response.setProgressBreakdown(buildProgressBreakdown(questionsToday, imagesToday, coverageOverall, questionTrend, imageTrend, coverageDelta));
        response.setStats(buildStats(questionsToday, imagesToday, coverageOverall, avgQuestionConfidence, questionTrend, imageTrend, coverageDelta, confidenceDelta));
        response.setInsights(buildInsights(recentQuestions));
        response.setTrends(buildTrendMetrics(avgQuestionConfidence, avgImageConfidence, questionsThisWeek, weeklyGrowth));
        response.setRoadmap(buildRoadmap(response.getHero().getProgressPercentage()));
        return response;
    }

    private DashboardHeroResponse buildHero(long questionsToday, long imagesToday, double coverage, double avgConfidence) {
        double questionProgress = ratio(questionsToday, DAILY_QUESTION_TARGET);
        double imageProgress = ratio(imagesToday, DAILY_IMAGE_TARGET);
        double coverageProgress = Math.min(100.0, coverage);
        int overallProgress = (int) Math.round((questionProgress + imageProgress + coverageProgress) / 3.0);

        DashboardHeroResponse hero = new DashboardHeroResponse();
        hero.setGoal(String.format("智能问答 %d/%d · 影像分析 %d/%d", questionsToday, DAILY_QUESTION_TARGET, imagesToday, DAILY_IMAGE_TARGET));
        hero.setStatus(String.format("运行%s · 平均问答置信度 %.0f%%", resolveStatusLabel(overallProgress), avgConfidence * 100));
        hero.setProgressPercentage(overallProgress);
        return hero;
    }

    private List<DashboardProgressItemResponse> buildProgressBreakdown(long questionsToday,
                                                                       long imagesToday,
                                                                       double coverage,
                                                                       double questionTrend,
                                                                       double imageTrend,
                                                                       double coverageDelta) {
        List<DashboardProgressItemResponse> list = new ArrayList<>();

        DashboardProgressItemResponse questionItem = new DashboardProgressItemResponse();
        questionItem.setLabel("智能问答履约");
        questionItem.setValue(String.format("今日 %d 条", questionsToday));
        questionItem.setPercentage(ratio(questionsToday, DAILY_QUESTION_TARGET));
        questionItem.setDescription("较昨日 " + formatTrend(questionTrend));
        list.add(questionItem);

        DashboardProgressItemResponse imageItem = new DashboardProgressItemResponse();
        imageItem.setLabel("影像分析执行");
        imageItem.setValue(String.format("今日 %d 份", imagesToday));
        imageItem.setPercentage(ratio(imagesToday, DAILY_IMAGE_TARGET));
        imageItem.setDescription("较昨日 " + formatTrend(imageTrend));
        list.add(imageItem);

        DashboardProgressItemResponse coverageItem = new DashboardProgressItemResponse();
        coverageItem.setLabel("档案结构化");
        coverageItem.setValue(String.format("覆盖率 %s", formatPercent(coverage)));
        coverageItem.setPercentage(Math.min(100.0, coverage));
        coverageItem.setDescription("周环比 " + formatTrend(coverageDelta));
        list.add(coverageItem);

        return list;
    }

    private List<DashboardStatCardResponse> buildStats(long questionsToday,
                                                       long imagesToday,
                                                       double coverage,
                                                       double avgConfidence,
                                                       double questionTrend,
                                                       double imageTrend,
                                                       double coverageDelta,
                                                       double confidenceDelta) {
        List<DashboardStatCardResponse> stats = new ArrayList<>();

        DashboardStatCardResponse qa = new DashboardStatCardResponse();
        qa.setKey("qa");
        qa.setTitle("智能问答");
        qa.setValue(String.valueOf(questionsToday));
        qa.setUnit("条");
        qa.setSubtitle("今日完成问诊");
        qa.setTrend(formatTrend(questionTrend));
        qa.setTrendType(resolveTrendType(questionTrend));
        qa.setAccent("rgba(37, 99, 235, 0.12)");
        qa.setColor("#2563eb");
        stats.add(qa);

        DashboardStatCardResponse images = new DashboardStatCardResponse();
        images.setKey("images");
        images.setTitle("影像分析");
        images.setValue(String.valueOf(imagesToday));
        images.setUnit("份");
        images.setSubtitle("今日完成影像");
        images.setTrend(formatTrend(imageTrend));
        images.setTrendType(resolveTrendType(imageTrend));
        images.setAccent("rgba(14, 165, 233, 0.12)");
        images.setColor("#0ea5e9");
        stats.add(images);

        DashboardStatCardResponse records = new DashboardStatCardResponse();
        records.setKey("records");
        records.setTitle("健康档案");
        records.setValue(formatDecimal(coverage));
        records.setUnit("%");
        records.setSubtitle("结构化覆盖率");
        records.setTrend(formatTrend(coverageDelta));
        records.setTrendType(resolveTrendType(coverageDelta));
        records.setAccent("rgba(34, 197, 94, 0.12)");
        records.setColor("#22c55e");
        stats.add(records);

        DashboardStatCardResponse confidence = new DashboardStatCardResponse();
        confidence.setKey("confidence");
        confidence.setTitle("AI 置信度");
        confidence.setValue(formatDecimal(avgConfidence * 100));
        confidence.setUnit("%");
        confidence.setSubtitle("近 50 条问答平均");
        confidence.setTrend(formatTrend(confidenceDelta));
        confidence.setTrendType(resolveTrendType(confidenceDelta));
        confidence.setAccent("rgba(124, 58, 237, 0.12)");
        confidence.setColor("#7c3aed");
        stats.add(confidence);

        return stats;
    }

    private List<DashboardInsightResponse> buildInsights(List<Question> recentQuestions) {
        if (recentQuestions == null || recentQuestions.isEmpty()) {
            return Collections.emptyList();
        }

        List<DashboardInsightResponse> insights = new ArrayList<>();
        for (Question question : recentQuestions) {
            DashboardInsightResponse insight = new DashboardInsightResponse();
            insight.setId(question.getId());
            insight.setCategory(resolveQuestionTypeDisplay(question.getQaType()));
            String headline = truncateText(question.getQuestion(), 48);
            insight.setHeadline(headline != null ? headline : "未填写问题内容");
            insight.setDetail(truncateText(question.getAnswer(), 72));
            insight.setConfidence(question.getConfidence());
            insight.setUpdatedAt(question.getCreatedAt());
            insights.add(insight);
        }
        return insights;
    }

    private List<DashboardTrendMetricResponse> buildTrendMetrics(double avgQuestionConfidence,
                                                                 double avgImageConfidence,
                                                                 long questionsThisWeek,
                                                                 double weeklyGrowth) {
        List<DashboardTrendMetricResponse> trends = new ArrayList<>();

        DashboardTrendMetricResponse qaConfidence = new DashboardTrendMetricResponse();
        qaConfidence.setLabel("问答置信度");
        qaConfidence.setPercentage((int) Math.round(avgQuestionConfidence * 100));
        qaConfidence.setTag("智能问答");
        qaConfidence.setTagType("success");
        qaConfidence.setTip("近 50 条问答平均");
        qaConfidence.setColor("#2563eb");
        trends.add(qaConfidence);

        DashboardTrendMetricResponse imageConfidence = new DashboardTrendMetricResponse();
        imageConfidence.setLabel("影像诊断置信度");
        imageConfidence.setPercentage((int) Math.round(avgImageConfidence * 100));
        imageConfidence.setTag("影像 AI");
        imageConfidence.setTagType("primary");
        imageConfidence.setTip("近 50 份影像平均");
        imageConfidence.setColor("#7c3aed");
        trends.add(imageConfidence);

        DashboardTrendMetricResponse weekly = new DashboardTrendMetricResponse();
        weekly.setLabel("本周问诊进度");
        weekly.setPercentage((int) Math.min(100, Math.round(ratio(questionsThisWeek, WEEKLY_QUESTION_TARGET))));
        weekly.setTag("运营指标");
        weekly.setTagType(weeklyGrowth >= 0 ? "success" : "warning");
        weekly.setTip("环比 " + formatTrend(weeklyGrowth));
        weekly.setColor("#f59e0b");
        trends.add(weekly);

        return trends;
    }

    private List<DashboardRoadmapItemResponse> buildRoadmap(int progressPercentage) {
        List<DashboardRoadmapItemResponse> roadmap = new ArrayList<>();

        roadmap.add(buildRoadmapItem("Day 1", "项目初始化与基础架构", "完成前后端分离、统一鉴权、CI/CD 基线。", "done"));
        roadmap.add(buildRoadmapItem("Day 2", "用户模块与安全体系", "打通注册登录、JWT 权限、数据加密。", "done"));
        roadmap.add(buildRoadmapItem("Day 3", "问答引擎融合", "构建中西医问答知识图谱，完成多轮对话流程。", "done"));
        roadmap.add(buildRoadmapItem("Day 4", "影像分析中心", "联通影像识别引擎与健康档案，支持结构化报告。", progressPercentage >= 70 ? "done" : "current"));
        roadmap.add(buildRoadmapItem("Day 5", "运营分析与体验升级", "打造全新交互体验与数据运营看板。", progressPercentage >= 85 ? "current" : "planned"));

        return roadmap;
    }

    private DashboardRoadmapItemResponse buildRoadmapItem(String day, String title, String description, String status) {
        DashboardRoadmapItemResponse item = new DashboardRoadmapItemResponse();
        item.setDay(day);
        item.setTitle(title);
        item.setDescription(description);
        item.setStatus(status);
        return item;
    }

    private double ratio(long value, int target) {
        if (target <= 0) {
            return 0.0;
        }
        return Math.min(100.0, value * 100.0 / target);
    }

    private double percentageChange(long current, long previous) {
        if (previous == 0) {
            return current == 0 ? 0.0 : 100.0;
        }
        return (current - previous) * 100.0 / previous;
    }

    private String formatTrend(double change) {
        if (Double.isNaN(change) || Double.isInfinite(change) || Math.abs(change) < 0.1) {
            return "持平";
        }
        return (change >= 0 ? "↑" : "↓") + formatDecimal(Math.abs(change)) + "%";
    }

    private String resolveTrendType(double change) {
        if (change > 0.5) {
            return "positive";
        }
        if (change < -0.5) {
            return "negative";
        }
        return "neutral";
    }

    private String formatPercent(double value) {
        return formatDecimal(value) + "%";
    }

    private String formatDecimal(double value) {
        BigDecimal decimal = BigDecimal.valueOf(value).setScale(1, RoundingMode.HALF_UP).stripTrailingZeros();
        return decimal.toPlainString();
    }

    private double averageConfidenceFromQuestions(List<Question> questions) {
        if (questions == null || questions.isEmpty()) {
            return 0.0;
        }
        double total = 0.0;
        int count = 0;
        for (Question question : questions) {
            BigDecimal confidence = question.getConfidence();
            if (confidence != null) {
                total += confidence.doubleValue();
                count++;
            }
        }
        return count == 0 ? 0.0 : total / count;
    }

    private double averageConfidenceFromImages(List<ImageRecord> records) {
        if (records == null || records.isEmpty()) {
            return 0.0;
        }
        double total = 0.0;
        int count = 0;
        for (ImageRecord record : records) {
            BigDecimal confidence = record.getConfidence();
            if (confidence != null) {
                total += confidence.doubleValue();
                count++;
            }
        }
        return count == 0 ? 0.0 : total / count;
    }

    private String resolveQuestionTypeDisplay(String qaType) {
        if (!StringUtils.hasText(qaType)) {
            return "智能问答";
        }
        try {
            QuestionType type = QuestionType.fromCode(qaType);
            return type.getDisplayName();
        } catch (Exception ex) {
            return "智能问答";
        }
    }

    private String truncateText(String value, int maxLength) {
        if (!StringUtils.hasText(value)) {
            return null;
        }
        if (value.length() <= maxLength) {
            return value;
        }
        return value.substring(0, maxLength) + "...";
    }

    private String resolveStatusLabel(int progress) {
        if (progress >= 85) {
            return "稳定";
        }
        if (progress >= 60) {
            return "良好";
        }
        return "需关注";
    }

    private Date toDate(LocalDateTime dateTime) {
        return Date.from(dateTime.atZone(ZoneId.systemDefault()).toInstant());
    }
}


